WebSocket supports sending both text and binary data through its send() method, with text sent as UTF-8 strings and binary sent as ArrayBuffer, Blob (browser), or Buffer (Node.js), while structured data like JSON requires serialization before sending.
The WebSocket API provides a unified send() method that accepts various data types, automatically framing them appropriately for transmission. The key distinction is between text frames and binary frames—WebSocket has separate opcodes for each. When you send a string, it's transmitted as a text frame with UTF-8 encoding. When you send binary data, it's transmitted as a binary frame. The receiving side can distinguish between them through the event.data type, allowing applications to handle different message formats appropriately.
String (text): Sent as UTF-8 encoded text frame. Ideal for human-readable messages, commands, and simple data .
ArrayBuffer: Sent as binary frame. Perfect for efficient transmission of typed data, images, audio, or any binary format .
Typed Arrays (Uint8Array, etc.): The underlying ArrayBuffer is sent; the view type isn't preserved .
Blob (browser): Sent as binary frame. Useful for file data without reading into memory first .
Buffer (Node.js): In Node.js, Buffer objects are accepted and sent as binary data .
DataView: The underlying ArrayBuffer is sent .
On the receiving side, the binary type must be configured to properly handle incoming binary data. The socket.binaryType property determines whether binary messages are delivered as Blob (default in browsers) or ArrayBuffer. This choice affects memory usage and how you process the data—Blobs are better for large files, while ArrayBuffers provide direct memory access for parsing.
Message framing: Since WebSocket preserves message boundaries, you don't need delimiters like newlines for separate messages .
Binary vs text: Use text for human-readable, debuggable protocols. Use binary for efficiency and when sending non-text data .
Message types: Design your protocol to distinguish message types. Common approaches include first-byte type identifiers or JSON with a 'type' field .
Length prefixing: For binary protocols, consider prefixing each message with a length field to help parsing .
Compression: Enable permessage-deflate extension for text-heavy protocols to reduce bandwidth .
In Node.js environments, the WebSocket API is similar but with Node-specific types. Libraries like 'ws' provide a WebSocket implementation that accepts Node.js Buffer objects and supports streaming. The key difference is that Node.js doesn't have Blob, but Buffer serves a similar purpose. For large data, Node.js WebSocket implementations often support backpressure handling through the socket.bufferedAmount property and drain events.
Choosing the right data format depends on your application needs. JSON over text is simple and debuggable but adds overhead. Binary protocols are more efficient but harder to debug. Many applications use a hybrid approach: JSON for control messages and binary for bulk data. The WebSocket API's flexibility in handling both text and binary makes it suitable for this mixed-mode communication, allowing you to optimize each part of your protocol independently.